package com.ebor.utils.exception;

import com.ebor.utils.common.HttpStatus;
import com.ebor.utils.common.Response;
import com.ebor.utils.utils.RequestUtils;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 异常统一处理
 *
 * @author C
 */
@Slf4j
@RestControllerAdvice
public class ExceptionManage {

    /**
     * 系统自定义异常处理
     */
    @ExceptionHandler(value = SysRuntimeException.class)
    public Response<?> sysRuntimeException(HttpServletRequest request, SysRuntimeException e) {
        Response<?> res = Response.error(e);
        logError(request, res, e);
        return res;
    }

    /**
     * MethodArgumentNotValidException处理
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public Response<?> sysRuntimeException(HttpServletRequest request, MethodArgumentNotValidException e) {
        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
        String message = allErrors.stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(";"));
        Response<?> res = Response.error(HttpStatus.PARAMS_ERROR.getRespCode(),HttpStatus.PARAMS_ERROR.getRespMsg() + ":" + message);
        logError(request, res, e);
        return res;
    }

    /**
     * HttpRequestMethodNotSupportedException处理
     */
    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    public Response<?> httpRequestMethodNotSupportedException(HttpServletRequest request, HttpRequestMethodNotSupportedException e) {
        Response<?> res = Response.error(HttpStatus.METHOD_EXCEPTION);
        logError(request, res, e);
        return res;
    }

    @ExceptionHandler(value = MethodArgumentTypeMismatchException.class)
    public Response<?> methodArgumentTypeMismatchException(HttpServletRequest request, MethodArgumentTypeMismatchException e) {
        Response<?> res = Response.error(HttpStatus.PARAMS_ERROR.getRespCode(), e.getMessage());
        logError(request, res, e);
        return res;
    }

    @ExceptionHandler(value = HttpMessageNotReadableException.class)
    public Response<?> httpMessageNotReadableException(HttpServletRequest request, HttpMessageNotReadableException e) {
        Response<?> res = Response.error(HttpStatus.PARAM_EXCEPTION);
        logError(request, res, e);
        return res;
    }

    @ExceptionHandler(value = ConstraintViolationException.class)
    public Response<?> constraintViolationException(HttpServletRequest request, ConstraintViolationException e) {
        Response<?> res = Response.error(HttpStatus.PARAMS_ERROR.getRespCode(), e.getMessage());
        logError(request, res, e);
        return res;
    }

    /**
     * 异常统一处理
     */
    @ExceptionHandler(value = Exception.class)
    public Response<?> exception(HttpServletRequest request, Exception e) {
        Response<?> res = Response.error(HttpStatus.UNKNOWN_EXCEPTION);
        logError(request, res, e);
        return res;
    }

    /**
     * 请求异常时打印日志
     */
    private void logError(HttpServletRequest request, Object res, Exception e){
        log.info("\nURL:{}\nHeaders:{}\nHTTP-Method:{}\nIP:{}\nparams:{}\nresult:{}", request.getRequestURL().toString(),
                RequestUtils.getHeaders(request), request.getMethod(), request.getRemoteAddr(), RequestUtils.getParameter(request),
                JSONObject.toJSON(res), e);
    }
}